{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "88242c51",
   "metadata": {},
   "source": [
    "## python 的位操作\n",
    "\n",
    "- **python 在存储数值的时候没有位数限制：正数左侧有无数个0，负数的左侧有无数的个1**\n",
    "- **计算机存储数据的时候，存储的是数据的补码**\n",
    "\n",
    "\n",
    "\n",
    "- **python中使用数据的补码，存储数据**\n",
    " - **原码：符号位+原始二进制形式**\n",
    " - **反码：原码符号位不变，其他位取反**\n",
    " - **补码：正数的补码是其自身，负数的补码是在原码的基础上，符号位不变，其他位取反后加1**\n",
    " \n",
    " \n",
    "- **python的位操作直接作用于数据的补码**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2847ac39",
   "metadata": {},
   "source": [
    "### python的位逻辑运算符\n",
    "- 与：`&`\n",
    "- 或: `|`\n",
    "- 非:`~`\n",
    "- 异或：`^`\n",
    "\n",
    "**对于异或有**\n",
    "`a^a=0`,  `a^a^a = a`"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd587c2e",
   "metadata": {},
   "source": [
    "### python 按位取反"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "6e79e521",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-6\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "print(~5)\n",
    "print(~(-5))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c36604d7",
   "metadata": {},
   "source": [
    "- 5的补码是` 0...000000101` 按位取反后 `1...11111010` 这个补码最高位是一个1，所以为负数，将这个补码恢复为对应的负数的原码（先取反码再加1），==》取反：`10...00000101` 再加1：`10...00000110`=-6\n",
    "\n",
    "- -5的原码是`1...00000101`->反码：`1...11111010` -> 补码：`1...11111011`, 对-5的补码按位取反：`0...00000100`,最高位为0，为正数原码和补码相同，所以为4\n",
    "\n",
    "### python 输出一个负数的补码对应的数值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "1ef7007a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-0b101\n",
      "0b101\n",
      "<class 'str'>\n"
     ]
    }
   ],
   "source": [
    "print(bin(-5))\n",
    "print(bin(5))\n",
    "print(type(bin(5)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a49798f1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0b11111111111111111111111111111011\n",
      "11111111111111111111111111111011\n",
      "0b101\n",
      "00000000000000000000000000000101\n"
     ]
    }
   ],
   "source": [
    "print(bin(-5&0xffffffff)) # 输出-5的后32位的补码形式，本身就是以补码形式存储的，我们只需要使用0xffffffff截取后32位就可以\n",
    "print(bin(-5&0xffffffff)[2:])\n",
    "print(bin(5&0xffffffff))\n",
    "chars = bin(5&0xffffffff)[2:].zfill(32)\n",
    "print(chars)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7eeddde7",
   "metadata": {},
   "source": [
    "bin(i) 会返回i的二进制的字符串形式，并且以‘ob’开头，并且会自动省略前面代表符号位的1，并且会强制忽略前导0\n",
    "如果想对固定位的数值进行操作，需要使用类似`(i&0xffff)`这样的按位与操作，截取后面16位（或者其他位）\n",
    "\n",
    "### 输出补码对应的数值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "64f232fc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4294967291\n",
      "0b11111111111111111111111111111011\n",
      "4294967291\n"
     ]
    }
   ],
   "source": [
    "chars = bin(-5&0xffffffff)  # -5 对应的32位的补码，\n",
    "print(-5&0xffffffff) # 输出-5的32位补码对应的数值\n",
    "print(chars)\n",
    "val = int(chars,2)  # 以二进制的形式读取字符串chars，返回二进制对应的数值\n",
    "print(val)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9fca8c86",
   "metadata": {},
   "source": [
    "由以上可知，直接读取补码`0b11111111111111111111111111111011`,默认为`0...11111111111111111111111111111011`（4294967291）,也就是默认会是放置前导0\n",
    "\n",
    "\n",
    "已知一个数的补码，求这个数的值，先根据补码的最高位判断正负，为正直接输出比较简单\n",
    "\n",
    "**下面我们展示：已知一个负数的补码，求负数**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "35657ce2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0b11111111111111111111111111111011\n",
      "4294967291\n",
      "按位取反：0b100\n",
      "-4294967292\n",
      "补码：0b101\n",
      "5\n",
      "-5\n"
     ]
    }
   ],
   "source": [
    "chars = '0b11111111111111111111111111111011'\n",
    "val_old = int(chars,2) # 读取二进制字符串\n",
    "print(bin(val_old&0xffffffffff))# 后32位\n",
    "print(val_old)  # 对应的数值\n",
    "val = val_old\n",
    "val = ~val # 按位取反\n",
    "print('按位取反：{}'.format(bin(val&0xffffffff)))\n",
    "print(val)\n",
    "val = (val+1)&0xffffffff # 加1 求补码对应的原码，注意这里的原码的符号位不正确，正确的处理的方法应该是保持符号位不变，我们这里先求绝对值，再处理符号位\n",
    "print('补码：{}'.format(bin(val&0xffffffff)))\n",
    "print(val)\n",
    "val = (-1)**((val_old>>31)&1)*val # 根最高位确定数值的符号\n",
    "print(val)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9dc85d75",
   "metadata": {},
   "source": [
    "### python 移位操作\n",
    "> python 只对整数进行移位操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "e02cc6a2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "<class 'int'>\n"
     ]
    }
   ],
   "source": [
    "print(3>>2)\n",
    "print(type(3>>2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c90bf8c",
   "metadata": {},
   "source": [
    "- 对正整数移位:  左移右侧补0，右移左侧补0， 不会改变符号\n",
    "- 对负整数移位： 左移右侧补0，右移左侧补1， 不会改变符号"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "20887620",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "8\n",
      "-2\n",
      "-8\n",
      "-64\n"
     ]
    }
   ],
   "source": [
    "print(4>>1)\n",
    "print(4<<1)\n",
    "\n",
    "print((-4)>>1)\n",
    "print((-4)<<1)\n",
    "print((-4)<<4)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "22e6cde2",
   "metadata": {},
   "source": [
    "- 4的补码`0000 0100`\n",
    "```\n",
    "4>>1 -> 右移1：`0000 0010` 2\n",
    "4<<1 -> 左移1：`0000 1000` 8\n",
    "```\n",
    "- -4的补码：`1111 1100`\n",
    "```\n",
    "(-4)>>1 -> 右移：`1111 1110`, 把补码还原为原码（先按位取反再+1），原码: `1000 0010` -2\n",
    "(-4)<<1 -> 左移：`1111 1000`, 把补码还原为原码（先按位取反再+1）, 原码：`1000 1000` -8\n",
    "(-4)<<4 -> 左移：`1100 0000`, 把补码还原为原码（先按位取反再+1）, 原码：`1100 0000` -64\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fbe8e8ff",
   "metadata": {},
   "source": [
    "### python 负数的整除与取模\n",
    "\n",
    "- `//`: 表示向下取整 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "47209b0e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "-3\n",
      "-3\n"
     ]
    }
   ],
   "source": [
    "print(5//2)\n",
    "print(-5//2)\n",
    "print(5//-2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bbcd3238",
   "metadata": {},
   "source": [
    "- `%`: 取整后余下的部分，$c=a\\%b, d=a//b  \\to  c=a - b*d$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "1d9ffc37",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "1\n",
      "-1\n"
     ]
    }
   ],
   "source": [
    "print(5%2)    # =5-5//2\n",
    "print(-5%2)   # =-5-(-5)//2\n",
    "print(5%(-2)) # =5-5//(-2)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
